
#include <BPainter>
#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BSonDocument>
#include <BStyle>
#include <BTextFormat>

#include "ServerWidget.h"

class AddressFormat : public BTextFormat
{
	virtual void styled(const BStyle* style) override
	{

	}
	virtual void changed(const BString& text) override
	{
		int split = text.find(':');
		_colorMap.reset();
		_colorMap.insert(0, BColor(0, 120, 0));
		_colorMap.insert(split, BColor(30, 40, 50));
		_colorMap.insert(split + 1, BColor(0, 60, 120));
	}

	virtual const BColor* color(int pos) const
	{
		auto it = _colorMap <= pos;
		if (it.valid())
			return &(*it);
		return 0;
	}

private:
	BMap<int, BColor>		_colorMap;
};

ServerWidget::ServerWidget()
{
	BHBoxLayout* topLayout = new BHBoxLayout();
	{
		BLabel* addressLabel = new BLabel("Server Address");
		_addressEdit = new BLineEdit();
		_addressEdit->setTextFormat(new AddressFormat());
		_startButton = new BButton(Graph_Circle_Fill, "Start");
		_startButton->setCheckable(true);
		topLayout->addWidget(addressLabel, 0);
		topLayout->addWidget(_addressEdit);
		topLayout->addWidget(_startButton, 0);
		this->setLayout(topLayout, Part_Top);
	}

	_dialogList = new DialogListWidget();

	BHBoxLayout* inputLayout = new BHBoxLayout();
	{
		_inputEdit = new BLineEdit();
		_sendButton = new BButton("send");
		inputLayout->addWidget(_inputEdit);
		inputLayout->addWidget(_sendButton, 0);
	}

	BVBoxLayout* vlayout = new BVBoxLayout(this);
	vlayout->addWidget(_dialogList);
	vlayout->addLayout(inputLayout, 0);

	_server = new BTcpServer();

	connect(_addressEdit, Signal_Clicked, &ServerWidget::slotAddressEdited);
	connect(_startButton, Signal_Clicked, &ServerWidget::slotStartButtonClicked);
	connect(_inputEdit, Signal_KeyPress, &ServerWidget::slotInputEditKeyDown);
	connect(_sendButton, Signal_Clicked, &ServerWidget::slotSendButtonClicked);
	connect(_server, Signal_NewConnection, &ServerWidget::slotNewConnection);

	_addressEdit->setText("127.0.0.1:1234");
}
ServerWidget::~ServerWidget()
{

}

bool ServerWidget::sendMessage()
{
	const BString& text = _inputEdit->text();
	if (text.empty())
		return false;
	BString message("message{");
	message << text << "}";
	_client->send(message);
	DialogListItem* item = new DialogListItem();
	item->setText(text);
	item->setIcon(this->asset());
	item->setAlign(Align_Left);
	_dialogList->addItem(item);
	_inputEdit->setText(BString());
	return true;
}

void ServerWidget::slotAddressEdited()
{

}
void ServerWidget::slotStartButtonClicked()
{
	if (_startButton->checked())
	{
		const BString& address = _addressEdit->text();
		BStringArray words = address.split(':');
		if (words.size() == 2)
		{
			int port = words[1].toInt();
			_server->bind(words[0], port);
			_server->listen(100);
			emit("server-started", address);
			BString infoText("start listen ");
			infoText << address << " successful.";
			DialogListItem* item = new DialogListItem();
			item->setText(infoText);
			item->setAlign(Align_Center);
			_dialogList->addItem(item);
		}
	}
	else
	{
		_server->close();
	}
	if (_server->state() == BSocket::State_Listening)
	{
		_startButton->setText("Close");
		_startButton->setColor(0, 200, 0);
	}
	else
	{
		_startButton->setText("Start");
		_startButton->setColor(0, 0, 0);
	}
}
void ServerWidget::slotInputEditKeyDown(BObject* object, const BValue& value)
{
	Key key = value;
	if (key == Key_Enter)
	{
		sendMessage();
	}
}
void ServerWidget::slotSendButtonClicked()
{
	sendMessage();
}
void ServerWidget::slotNewConnection(BObject* object, const BValue& value)
{
	_client = (BTcpSocket*)value;
	if (_client)
	{
		BString infoText("new connection ");
		infoText << _client->address() << ":" << _client->port();
		DialogListItem* item = new DialogListItem();
		item->setText(infoText);
		item->setAlign(Align_Center);
		_dialogList->addItem(item);

		connect(_client, Signal_Disconnected, &ServerWidget::slotClientDisconnected);
		connect(_client, Signal_ReadyRead, &ServerWidget::slotClientReadyRead);
		connect(_client, Signal_BytesSent, &ServerWidget::slotClientBytesSent);
	}
}
void ServerWidget::slotClientDisconnected(BObject* object, const BValue& value)
{
	_client = 0;
}
void ServerWidget::slotClientReadyRead(BObject* object, const BValue& value)
{
	_buffer.seek(_buffer.size());
	int size = _client->recv(_buffer);
	_buffer.seek(0);
	BSonDocument doc;
	if (BSonNode* node = doc.read(_buffer))
	{
		if (node->name() == "login")
		{
			const BString& username = node->attrib("username");
			const BString& password = node->attrib("password");
			BString infoText("login : ");
			infoText << "username[" << username << ']';
			infoText << "password[" << password << ']';
			_client->setName(username);
			DialogListItem* item = new DialogListItem();
			item->setText(infoText);
			item->setIcon(_clientIcon);
			item->setAlign(Align_Center);
			_dialogList->addItem(item);
		}
		else if (node->name() == "message")
		{
			const BString& text = node->text();
			DialogListItem* item = new DialogListItem();
			item->setName(_client->name());
			item->setText(text);
			item->setIcon(_clientIcon);
			item->setAlign(Align_Right);
			item->setForm(Form_TextIcon);
			_dialogList->addItem(item);
		}
		_buffer.bytes().remove(0, _buffer.offset());
	}
}
void ServerWidget::slotClientBytesSent(BObject* object, const BValue& value)
{

}

void ServerWidget::updateEvent(const BEvent& event)
{
	if (_client)
	{
		_inputEdit->setEnabled(true);
		_sendButton->setEnabled(true);
	}
	else
	{
		_inputEdit->setEnabled(false);
		_sendButton->setEnabled(false);

	}
}
void ServerWidget::styleEvent(const BEvent& event)
{
	const BStyle* style = event.value();
	this->setAsset(style->icon("server"));
	_clientIcon = style->icon("client");
}


